//    Copyright (C) Kherty.  All rights reserved.
#region

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.Contracts;
using OpenLS.Spreadsheet.Extensibility;
using OpenLS.Spreadsheet.Parsing;

#endregion

namespace OpenLS.Spreadsheet.Expressions
{
    internal class NameExpression : CellEnumeratorExpression
    {
        private readonly string _name;
        private readonly Worksheet _worksheet;
        private Workbook _workbook;

        public override IEnumerable<Expression> GetSubExpressions()
        {
            yield break;
        }

        internal override Expression Transposed(Cell target)
        {
            return this;
        }
        public NameExpression(Worksheet worksheet, string name)
        {
            Contract.Requires(name != null);
            Contract.Requires(worksheet != null);
            Contract.Requires(name != "TRUE");
            Contract.Requires(name != "FALSE");
            Contract.Requires(!name.Contains("%"));
            _name = name;
            _worksheet = worksheet;
        }

        public NameExpression(Workbook workbook, string name)
        {
            Contract.Requires(name != null);
            Contract.Requires(workbook != null);
            Contract.Requires(name != "TRUE");
            Contract.Requires(name != "FALSE");
            Contract.Requires(!name.Contains("%"));
            this._workbook = workbook;
            _name = name;
        }

        public string Name
        {
            get { return _name; }
        }

        public override Expression Offset(CellRelativeAddress a)
        {
            return this;
        }

        public override Worksheet Worksheet
        {
            get { throw new NotImplementedException(); }
        }

        public Worksheet Caller
        {
            get { return _worksheet; }
        }

        public override string GetText(TextContext context)
        {
            return Name;
        }

        public override IEnumerable<IDependencyNode> GetPrecedents(EvaluationContext context)
        {
            yield return context.Worksheet.Workbook.NameManager.GetNameNode(Name);
            /* yield break;
            Range r = Worksheet.GetRange(Name);
            if (r != null)
                foreach (Cell c in r.GetNonEmptyCells())
                    yield return c;*/
        }

        protected override object GetObjectImp(EvaluationContext context)
        {
            Range r = null;
            if (Caller != null)
            {
                r = Caller.GetRange(Name); //\\ problem here
                if (r is SingleCellRange)
                    return r.FirstCell;
            }
            if (r == null)
            {
                var definedName = GetDefinedName();
                if (definedName != null)
                {
                    ExpressionParser parser;
                    if (Caller != null)
                        parser = new ExpressionParser(Caller, null, LocalizationMode.NonLocalized, CellReferenceMode.Dynamic);
                    else
                        parser = new ExpressionParser(this.Workbook, LocalizationMode.NonLocalized, CellReferenceMode.Dynamic);
                    Expression exp1 = parser.Expression("=" + definedName.Formula);
                    if (exp1 is NameExpression)
                    {
                        NameExpression ne = (NameExpression) exp1;
                        if (this._name == ne._name && this._worksheet == ne._worksheet)
                            return Errors.NameError;
                    }
                    return exp1.GetObject(context);
                }
                return Errors.NameError;
            }
            return r;
        }
        Workbook Workbook{get{if (Caller != null) return Caller.Workbook;
            return _workbook;
        }}
        internal DefinedName GetDefinedName()
        {
            var definedName = Enumerable.FirstOrDefault(this.Workbook.DefinedNames, n => n.Name == Name && n.LocalSheet == Caller);
            if (definedName == null)
                definedName = Enumerable.FirstOrDefault(this.Workbook.DefinedNames, n => n.Name == Name && n.LocalSheet == null);
            return definedName;    
        }

        protected internal override ICellEnumerator GetCellsValue(EvaluationContext context)
        {
            object o = GetObject(context);
            if (o is Range)
            {
                var r = (Range)o;
                if (r.ColumnSpan == 1)
                {
                    return r.Worksheet[context.Target.Row.Index, r.TopLeftCell.Column.Index];
                }
                if (r.RowSpan == 1)
                {
                    return r.Worksheet[r.TopLeftCell.Row.Index, context.Target.Column.Index];
                }
                return new CellError(Errors.ValueError);
            }
            if (o is Cell)
                return ((Cell)o);
            return (ICellEnumerator) o;
        }
        public override object GetValue(EvaluationContext context)
        {
            object o = GetObject(context);
            if (o is Range)
            {
                var r = (Range) o;
                if (r.ColumnSpan == 1)
                {
                    return r.Worksheet[context.Target.Row.Index, r.TopLeftCell.Column.Index].Value;
                }
                if (r.RowSpan == 1)
                {
                    return r.Worksheet[r.TopLeftCell.Row.Index, context.Target.Column.Index].Value;
                }
                return Errors.ValueError;
            }
            if (o is Cell)
                return ((Cell) o).Value;
            return o;
        }
    }
}